package com.vhall.component.service.lottery.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.lottery.LotteryMapper;
import com.vhall.component.dao.lottery.LotteryRecordMapper;
import com.vhall.component.dao.lottery.LotteryUserMapper;
import com.vhall.component.entity.account.AccountEntity;
import com.vhall.component.entity.account.vo.AccountVO;
import com.vhall.component.entity.export.ExportEntity;
import com.vhall.component.entity.lottery.entity.LotteryAwardEntity;
import com.vhall.component.entity.lottery.entity.LotteryEntity;
import com.vhall.component.entity.lottery.entity.LotteryRecordEntity;
import com.vhall.component.entity.lottery.vo.*;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.enums.LotteryTypeEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.Constants;
import com.vhall.component.service.account.AccountService;
import com.vhall.component.service.export.ExportService;
import com.vhall.component.service.lottery.LotteryConsoleService;
import com.vhall.component.service.room.RoomInnerService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author longzhen.gong
 * @date 2021/6/25 13:40
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class LotteryConsoleServiceImpl implements LotteryConsoleService {

    private final LotteryRecordMapper lotteryRecordMapper;

    private final LotteryMapper lotteryMapper;

    private final ExportService exportService;

    private final LotteryUserMapper lotteryUserMapper;

    @Autowired
    private AccountService accountService;

    private final RoomInnerService roomInnerFacade;

    @Override
    public LotteryGetsRspVO gets(LotteryListInfoReqVo reqVo) {
        int page = reqVo.getPage() == null ? 1 : reqVo.getPage();
        int pageSize = reqVo.getPageSize() == null ? 10 : reqVo.getPageSize();
        int offset = (page - 1) * pageSize;


        LocalDateTime beginTime = LocalDateTime.now();
        LocalDateTime endTime = LocalDateTime.now();
        if (StringUtils.isNotBlank(reqVo.getBeginTime())) {
            beginTime = DateUtil.parseLocalDateTime(reqVo.getBeginTime(), DatePattern.NORM_DATE_PATTERN);
            beginTime = beginTime.truncatedTo(ChronoUnit.DAYS);
        }
        if (StringUtils.isNotBlank(reqVo.getEndTime())) {
            endTime = DateUtil.parseLocalDateTime(reqVo.getEndTime(), DatePattern.NORM_DATE_PATTERN);
            endTime = endTime.with(LocalTime.MAX);
        }

        LambdaQueryWrapper<LotteryEntity> queryWrapper = Wrappers.<LotteryEntity>lambdaQuery()
                .eq(StringUtils.isNotBlank(reqVo.getRoomId()), LotteryEntity::getSourceId, reqVo.getRoomId())
                .ge(StringUtils.isNotBlank(reqVo.getBeginTime()), LotteryEntity::getCreatedAt, beginTime)
                .le(StringUtils.isNotBlank(reqVo.getEndTime()), LotteryEntity::getCreatedAt, endTime);
        // 获取count
        Integer count = lotteryMapper.selectCount(queryWrapper);
        if (Constants.SORT_ASC.equalsIgnoreCase(reqVo.getSortType())) {
            queryWrapper.orderByAsc(LotteryEntity::getCreatedAt);
        } else {
            queryWrapper.orderByDesc(LotteryEntity::getCreatedAt);
        }
        queryWrapper.last("limit " + offset + "," + pageSize);
        List<LotteryVO> collect = lotteryMapper.selectList(queryWrapper).parallelStream().map(lottery -> {
            LotteryVO lotteryVO = new LotteryVO();
            BeanUtils.copyProperties(lottery, lotteryVO);
//            lotteryVO.setAwardSnapshoot(getAwardSnapShoot(lottery.getAwardSnapshoot()));
            lotteryVO.setLeftSeconds(getLeftSeconds(lottery.getBeginTime()));
            // BeanUtils.copyProperties不会把LocalDateTime复制给Date
            lotteryVO.setCreatedAt(lottery.getCreatedAt() == null ? null : Date.from(lottery.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant()));
            lotteryVO.setUpdatedAt(lottery.getUpdatedAt() == null ? null : Date.from(lottery.getUpdatedAt().atZone(ZoneId.systemDefault()).toInstant()));
            lotteryVO.setDeletedAt(lottery.getDeletedAt() == null ? null : Date.from(lottery.getDeletedAt().atZone(ZoneId.systemDefault()).toInstant()));
            LambdaQueryWrapper<LotteryRecordEntity> lambdaQueryWrapper = Wrappers.lambdaQuery();
            lambdaQueryWrapper.eq(LotteryRecordEntity::getLotteryId, lottery.getId());
            lotteryVO.setLotteryNumber(lotteryRecordMapper.selectCount(lambdaQueryWrapper));
            return lotteryVO;
        }).collect(Collectors.toList());
        LotteryGetsRspVO rsp = new LotteryGetsRspVO();
        BeanUtils.copyProperties(reqVo, rsp);
        rsp.setCount(count);
        rsp.setList(collect);
        rsp.setLimit(pageSize);
        rsp.setOffset(offset);
        rsp.setSortType(Constants.SORT_ASC.equalsIgnoreCase(reqVo.getSortType()) ? Constants.SORT_ASC : Constants.SORT_DESC);
        rsp.setSourceId(reqVo.getRoomId());
        return rsp;
    }

    private AwardVO getAwardSnapShoot(String snapshoot) {
        if (StringUtils.isNotBlank(snapshoot)) {
            LotteryAwardEntity award = JSON.parseObject(snapshoot, LotteryAwardEntity.class);
            AwardVO awardVO = new AwardVO();
            BeanUtils.copyProperties(award, awardVO);
            return awardVO;
        }
        return null;
    }

    /**
     * 获取抽奖开始剩余秒数
     *
     * @param beginTime 开始时间
     * @return 剩余秒数
     */
    private Integer getLeftSeconds(Date beginTime) {
        if (beginTime == null || System.currentTimeMillis() >= beginTime.getTime()) {
            return 0;
        }
        return Math.toIntExact((beginTime.getTime() - System.currentTimeMillis()) / 1000);
    }

    @Override
    public LotteryUsersGetRspVO usersGet(LotteryUsersGetReqVO reqVo) {
        int page = Optional.ofNullable(reqVo.getPage()).orElse(1);
        int pageSize = Optional.ofNullable(reqVo.getPageSize()).orElse(10);
        int offset = (page - 1) * pageSize;
        LambdaQueryWrapper<LotteryRecordEntity> queryWrapper = Wrappers.<LotteryRecordEntity>lambdaQuery()
                .eq(StringUtils.isNotBlank(reqVo.getRoomId()), LotteryRecordEntity::getSourceId, reqVo.getRoomId())
                .eq(StringUtils.isNotBlank(reqVo.getLotteryId()), LotteryRecordEntity::getLotteryId, Long.parseLong(reqVo.getLotteryId()))
                .eq(StringUtils.isNotBlank(reqVo.getLotteryUserId()), LotteryRecordEntity::getLotteryUserId, reqVo.getLotteryUserId());
        if (Constants.SORT_ASC.equalsIgnoreCase(reqVo.getSortType())) {
            queryWrapper.orderByAsc(LotteryRecordEntity::getCreatedAt);
        } else {
            queryWrapper.orderByDesc(LotteryRecordEntity::getCreatedAt);
        }
        // 获取count
        Integer count = lotteryRecordMapper.selectCount(queryWrapper);
        queryWrapper.last("limit " + offset + "," + pageSize);
        List<LotteryUserVO> collect = new ArrayList<>();
        List<LotteryRecordEntity> lotteryRecordEntities = lotteryRecordMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(lotteryRecordEntities)) {
            // 查询account表获取username.
            final String lotteryId = reqVo.getLotteryId();
            final LotteryEntity lotteryEntity = lotteryMapper.selectById(Long.parseLong(lotteryId));
            List<AccountVO> accounts = new ArrayList<>();
            String ids = lotteryRecordEntities.parallelStream().map(LotteryRecordEntity::getLotteryUserId).collect(Collectors.joining(","));
            //判断是否是自定义列表的抽奖，如果是 则从lotteryUser中查询，否则从account中查询
            if (!LotteryTypeEnum.CUSTOM_LIST.lotteryTypeValue.equals(lotteryEntity.getLotteryType())) {
                accounts = accountService.listByIds(ids);
            }
            List<AccountVO> finalAccounts = accounts;
            collect = lotteryRecordEntities.parallelStream().map(lotteryUser -> buildLotteryUserVO(lotteryEntity, finalAccounts, lotteryUser)).collect(Collectors.toList());
        }
        LotteryUsersGetRspVO rspVo = new LotteryUsersGetRspVO();
        rspVo.setCount(count);
        BeanUtils.copyProperties(reqVo, rspVo);
        rspVo.setList(collect);
        LotteryEntity lottery = lotteryMapper.selectById(reqVo.getLotteryId());
        if (lottery != null) {
//            rspVo.setAwardSnapshoot(getAwardSnapShoot(lottery.getAwardSnapshoot()));
            rspVo.setCreatorId(lottery.getCreatorId());
            rspVo.setSourceId(lottery.getSourceId());
            rspVo.setLotteryId(lottery.getId());
        }
        rspVo.setLimit(pageSize);
        rspVo.setOffset(offset);
        rspVo.setSortType(Constants.SORT_ASC.equalsIgnoreCase(reqVo.getSortType()) ? Constants.SORT_ASC : Constants.SORT_DESC);
        return rspVo;
    }

    /**
     * 构建中奖记录信息
     *
     * @param lotteryEntity 中奖信息
     * @param finalAccounts 中奖相关用户账户信息列表
     * @param lotteryUser   中奖记录信息
     * @return LotteryUserVO
     */
    private LotteryUserVO buildLotteryUserVO(LotteryEntity lotteryEntity, List<AccountVO> finalAccounts, LotteryRecordEntity lotteryUser) {
        LotteryUserVO lotteryUserVO = new LotteryUserVO();
        BeanUtils.copyProperties(lotteryUser, lotteryUserVO);
        if ("{}".equals(lotteryUserVO.getLotteryUserRemark())) {
            lotteryUserVO.setLotteryUserRemark("");
        }
        lotteryUserVO.setUserName(lotteryUserVO.getLotteryUserName());
        if (!LotteryTypeEnum.CUSTOM_LIST.lotteryTypeValue.equals(lotteryEntity.getLotteryType())) {
            final Optional<AccountVO> first = finalAccounts.stream().filter(item -> item.getAccountId().toString().equals(lotteryUserVO.getLotteryUserId())).findFirst();
            if (first.isPresent()) {
                boolean userNameBlank = StringUtils.isBlank(lotteryUserVO.getLotteryUserName());
                boolean phoneBlank = StringUtils.isBlank(lotteryUserVO.getLotteryUserPhone());
                final AccountVO accountVO = first.get();
                lotteryUserVO.setUserName(accountVO.getUsername());
                if (userNameBlank) {
                    lotteryUserVO.setLotteryUserNickname(accountVO.getNickname());
                }
                if (phoneBlank) {
                    lotteryUserVO.setLotteryUserPhone(accountVO.getPhone().toString());
                }
            }
        }
        return lotteryUserVO;
    }

    @Override
    public Boolean exportLottery(LotteryExportReqVO lotteryExportReqVO) {
        RoomsEntityDTO roomInfo = roomInnerFacade.getRoomInfo(lotteryExportReqVO.getRoomId());
        if (roomInfo == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        LocalDateTime beginTime = LocalDateTime.now();
        LocalDateTime endTime = LocalDateTime.now();
        if (StringUtils.isNotBlank(lotteryExportReqVO.getBeginTime())) {
            beginTime = DateUtil.parseLocalDateTime(lotteryExportReqVO.getBeginTime(), DatePattern.NORM_DATE_PATTERN);
            beginTime = beginTime.truncatedTo(ChronoUnit.DAYS);
        }
        if (StringUtils.isNotBlank(lotteryExportReqVO.getEndTime())) {
            endTime = DateUtil.parseLocalDateTime(lotteryExportReqVO.getEndTime(), DatePattern.NORM_DATE_PATTERN);
            endTime = endTime.with(LocalTime.MAX);
        }
        Token token = TokenThreadLocal.getToken();
        Integer accountId = token.getAccountId();
        String subject = roomInfo.getSubject();
        if (subject.length() > 20) {
            subject = subject.substring(0, 20);
        }
        String fileName = subject + "-中奖明细-" + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN) + RandomUtil.randomNumbers(4);
        ExportEntity ee = new ExportEntity();
        String[] header = {"直播ID", "直播名称", "抽奖ID", "抽奖时间", "抽奖方式", "奖品类型", "奖品内容", "昵称", "手机号", "客户号", "收件人姓名", "收件人手机号", "邮寄地址"};
        Map<String, Object> param = new HashMap<>(8);
        param.put("file_name", fileName);
        param.put("account_id", accountId);
        param.put("begin_time", DateUtil.formatLocalDateTime(beginTime));
        param.put("end_time", DateUtil.formatLocalDateTime(endTime));
        param.put("room_id", lotteryExportReqVO.getRoomId());
        param.put("sort_type", StringUtils.isBlank(lotteryExportReqVO.getSortType()) ? Constants.SORT_DESC : lotteryExportReqVO.getSortType());
        ee.setSourceId(lotteryExportReqVO.getRoomId());
        ee.setTitle(JSON.toJSONString(header));
        ee.setParams(JSON.toJSONString(param));
        ee.setExt("csv");
        ee.setExport("lottery");
        ee.setRoomId(lotteryExportReqVO.getRoomId());
        ee.setIlId(roomInfo.getIlId());
        ee.setAccountId(accountId);
        ee.setFileName(fileName);
        ee.setCallback("lotteryService:lotteryExport");
        exportService.createExport(ee);
        return true;
    }

    @Override
    public void delWinner(Integer accountId) {
        LambdaQueryWrapper<LotteryRecordEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(LotteryRecordEntity::getLotteryUserId, accountId);
        lotteryRecordMapper.delete(queryWrapper);
    }

    @Override
    public LotteryWinnerPageVO getLotteryWinner(Integer lotteryId, String roomId, int pageNum, int pageSize) {
        LotteryWinnerPageVO lotteryWinnerPageVO = new LotteryWinnerPageVO();
        Page<LotteryRecordEntity> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<LotteryRecordEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(LotteryRecordEntity::getLotteryId, lotteryId);
        queryWrapper.eq(LotteryRecordEntity::getSourceId, roomId);
        page = lotteryRecordMapper.selectPage(page, queryWrapper);
        List<LotteryWinnerVO> list = new ArrayList<>();
        for (LotteryRecordEntity lotteryRecordEntity : page.getRecords()){
            LotteryWinnerVO vo = new LotteryWinnerVO();
            vo.setLotteryId(lotteryId);
            vo.setWinnerUserId(Integer.parseInt(lotteryRecordEntity.getLotteryUserId()));
            vo.setWinnerNickname(lotteryRecordEntity.getLotteryUserNickname());
            AccountEntity accountEntity = accountService.getById(Integer.parseInt(lotteryRecordEntity.getLotteryUserId()));
            String phone = String.valueOf(accountEntity.getPhone());
            vo.setWinnerPhone(String.valueOf(PhoneUtil.hideBetween(phone)));
            vo.setCsuid(accountEntity.getCustid());
            vo.setWinnerNickname(accountEntity.getNickname());
            vo.setLotteryDate(lotteryRecordEntity.getCreatedAt());
            vo.setLotteryUsername(lotteryRecordEntity.getLotteryUserName());
            vo.setLotteryPhone(lotteryRecordEntity.getLotteryUserPhone());
            vo.setLotteryAddress(lotteryRecordEntity.getLotteryUserRemark());
            list.add(vo);
        }
        lotteryWinnerPageVO.setList(list);
        lotteryWinnerPageVO.setPages(page.getPages());
        lotteryWinnerPageVO.setCurrentPage(pageNum);
        lotteryWinnerPageVO.setCurrentSize(page.getSize());
        lotteryWinnerPageVO.setTotal(page.getTotal());
        return lotteryWinnerPageVO;
    }

}
